﻿using Pay.Core;
using Pay.Data;
using Pay.DTO;
using Pay.IService;
using Pay.Service.Cache;
using Pay.TO;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Pay.Service {
    public class NoticeService : ServiceBase, INoticeService, IDisposable {
        public IMessagePushService _MessagePushService;
        private IUnitOfWork _iUnitOfWork;
        private IMerchantService _merchantService;
        public NoticeService(IUnitOfWork iUnitOfWork, IMessagePushService MessagePushService, IMerchantService merchantService) : base(iUnitOfWork) {
            _iUnitOfWork = iUnitOfWork;
            _MessagePushService = MessagePushService;
            _merchantService = merchantService;
        }

        /// <summary>
        /// 获得公告列表
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public PagedResult<notice_dto> GetNotices(NoticeQuery query) {
            var filter = PredicateBuilder.True<Notice>();
            if (!string.IsNullOrEmpty(query.title))
                filter = filter.And(c => c.Title == query.title);
            if (!string.IsNullOrEmpty(query.status)) {
                int value = int.Parse(query.status);
                filter = filter.And(c => c.Status == (ENoticeStatus)value);
            }
            if (!string.IsNullOrEmpty(query.begin_time)) {
                DateTime time = DateTime.Parse(query.begin_time);
                filter = filter.And(c => c.ReleaseTime >= time);
            }
            if (!string.IsNullOrEmpty(query.end_time)) {
                DateTime time = DateTime.Parse(query.end_time).AddDays(1);
                filter = filter.And(c => c.ReleaseTime <= time);
            }
            var result = context.Notice.FromCachePaged<Notice, notice_dto>(query.page, query.size, filter, orderBy => orderBy.OrderBy(o => o.Status).ThenByDescending(c => c.Id));
            return result;
        }

        /// <summary>
        /// 获得公告
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public notice_dto GetNotice(long id) {
            return context.Notice.Find(id).ToDtoObject<notice_dto>();
        }

        /// <summary>
        /// 新增公告
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public int AddNotice(notice_dto dto) {
            dto.create_time = DateTime.Now;
            if (dto.status == ENoticeStatus.Published)
                dto.release_time = DateTime.Now;
            if (dto.status == ENoticeStatus.Deleted || dto.status == ENoticeStatus.Unpublished)
                dto.release_time = null;
            Notice model = new Notice();
            dto.ToDtoObject(model);
            context.Notice.Add(model);
            int result = _iUnitOfWork.Commit("Notice");
            if (dto.status == ENoticeStatus.Published) {
                PushNotice(model.Id);
            }
            return result;
        }

        /// <summary>
        /// 更新公告
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public int UpdateNotice(notice_dto dto) {
            Notice model = context.Notice.FindById(dto.id);
            dto.ToDtoObject(model);
            if (model.Status == ENoticeStatus.Published)
                model.ReleaseTime = DateTime.Now;
            int result = _iUnitOfWork.Commit("Notice");

            if (dto.status == ENoticeStatus.Published) {
                PushNotice(model.Id);
            }
            return result;
        }

        /// <summary>
        /// 逻辑删除公告（仅后台调用）
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public int DeleteNotice(long id) {
            var notice = context.Notice.FindById(id);
            notice.Status = ENoticeStatus.Deleted;
            int result = _iUnitOfWork.Commit("Notice");
            return result;
        }

        /// <summary>
        /// 发布公告
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public int PublishNotice(long id) {
            var notice = context.Notice.FindById(id);
            notice.Status = ENoticeStatus.Published;
            notice.ReleaseTime = DateTime.Now;
            int result = _iUnitOfWork.Commit("Notice");
            PushNotice(notice.Id);
            return result;
        }


        #region APP_API接口
        /// <summary>
        /// 获得APP最新首页公告
        /// </summary>
        /// <returns></returns>
        public notice_dto GetAppIndexNotice(long userId) {
            notice_dto result = null;
            if (userId > 0) {
                merchant_dto user = _merchantService.Get(userId);
                DateTime? time = user?.create_time;
                var q = from n in context.Notice.Where(c => c.Type == ENoticeType.APP && c.Status == ENoticeStatus.Published)
                        join nu in context.NoticeUserReadHis.Where(o => o.UserId == userId) on n.Id equals nu.NoticeId into t1
                        from tnu in t1.DefaultIfEmpty()
                        where ((time == null || n.CreateTime > time) && (tnu == null || tnu.IsDeleted == false))
                        select new notice_dto() {
                            id = n.Id,
                            title = n.Title,
                            type = n.Type,
                            content = n.Content,
                            click_num = n.ClickNum,
                            create_time = n.CreateTime,
                            release_time = n.ReleaseTime,
                            status = n.Status,
                            url = n.Url,
                            isRead = tnu != null ? true : false
                        };
                result = q.OrderByDescending(o => o.release_time).FirstOrDefault();
            }
            if (userId == 0 || result == null)
                result = context.Notice.Where(o => o.Status == ENoticeStatus.Published && (o.Type == ENoticeType.APP)).OrderByDescending(o => o.ReleaseTime).FromCacheFirstOrDefault<Notice, notice_dto>("Notice");
            return result;
        }
        /// <summary>
        /// 获得APP公告列表
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public PagedResult<notice_dto> GetAppNoticePageList(NoticeApiQuery query, long userId) {
            var user = _merchantService.Get(userId);
            var q = from n in context.Notice.Where(c => c.Type == (ENoticeType)query.type)
                    join nu in context.NoticeUserReadHis.Where(o => o.UserId == userId) on n.Id equals nu.NoticeId into t1
                    from tnu in t1.DefaultIfEmpty()
                    where (n.Status == ENoticeStatus.Published && n.CreateTime > user.create_time && (tnu == null || tnu.IsDeleted == false))
                    select new notice_dto() {
                        id = n.Id,
                        title = n.Title,
                        type = n.Type,
                        content = n.Content,
                        click_num = n.ClickNum,
                        create_time = n.CreateTime,
                        release_time = n.ReleaseTime,
                        status = n.Status,
                        url = n.Url,
                        isRead = tnu != null ? true : false
                    };
            var count = q.Count();
            if (count > 0) {
                var rows = q.OrderByDescending(c => c.release_time).Skip((query.page - 1) * query.size).Take(query.size).ToList();
                var result = new PagedResult<notice_dto>(rows, count, query.page, query.size);
                return result;
            } else {
                var data = GetAppIndexNotice(userId);
                //data.isRead = false;
                var result = new PagedResult<notice_dto>(data == null ? new List<notice_dto>() : new List<notice_dto> { data }, data != null ? 1 : 0, query.page, query.size);
                return result;
            }
        }
        /// <summary>
        /// App获得公告详情
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public notice_dto AppGetNotice(long id, long userId) {
            var model = context.Notice.FindById(id);
            //model.ClickNum = model.ClickNum + 1;//增加点击次数
            //记录用户阅读记录
            if (!context.NoticeUserReadHis.Exist(o => o.UserId == userId && o.NoticeId == id)) {
                NoticeUserReadHis noticeUserReadHis = new NoticeUserReadHis() { UserId = userId, NoticeId = id, CreateTime = DateTime.Now };
                context.NoticeUserReadHis.Add(noticeUserReadHis);
            }
            _iUnitOfWork.Commit();

            return model.ToDtoObject<notice_dto>();
        }
        /// <summary>
        /// 消息公告
        /// </summary>
        /// <returns></returns>
        public notice_message_dto GetNoticMessage(long userId) {
            notice_message_dto model = new notice_message_dto();
            var q = from n in context.Notice
                    join nu in context.NoticeUserReadHis.Where(o => o.UserId == userId) on n.Id equals nu.NoticeId into t1
                    from tnu in t1.DefaultIfEmpty()
                    where (n.Status == ENoticeStatus.Published && n.Type != ENoticeType.Marketing && (tnu == null || tnu.IsDeleted == false))
                    select new notice_dto() {
                        id = n.Id,
                        title = n.Title,
                        type = n.Type,
                        content = n.Content,
                        click_num = n.ClickNum,
                        create_time = n.CreateTime,
                        release_time = n.ReleaseTime,
                        status = n.Status,
                        url = n.Url,
                        isRead = tnu != null ? true : false
                    };
            model.notice_num = q.Where(s => s.type == ENoticeType.APP && s.isRead == false).Count();
            var notice = q.Where(s => s.type == ENoticeType.APP).OrderByDescending(s => s.create_time).FirstOrDefault();
            model.notice_title = notice != null ? notice.title : "";
            //model.sys_msg_num = q.Where(s => s.type == ENoticeType.SystemMsg && s.isRead == false).Count();
            //var sysMsg = q.Where(s => s.type == ENoticeType.SystemMsg).OrderByDescending(s => s.create_time).FirstOrDefault();
            //model.sys_msg_title = sysMsg != null ? sysMsg.title : "";
            model.message_num = context.MessagePushs.Where(s => s.IsRead == false && s.MerchantId == userId && s.Type == MsgType.None).Count();
            var message = context.MessagePushs.Where(s => s.MerchantId == userId && s.Type == MsgType.None).OrderByDescending(s => s.CreateTime).FirstOrDefault();
            model.message_title = message == null ? "" : message.Title;
            return model;
        }

        /// <summary>
        /// 未读数量
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public int GetUnReads(long userId) {
            var user = _merchantService.Get(userId);
            var notice_count = (from n in context.Notice
                                join nu in context.NoticeUserReadHis.Where(o => o.UserId == userId) on n.Id equals nu.NoticeId into t1
                                from tnu in t1.DefaultIfEmpty()
                                where n.Status == ENoticeStatus.Published && n.Type == ENoticeType.APP && tnu == null && n.CreateTime > user.create_time && (tnu == null || tnu.IsDeleted == false)
                                select n.Id).Count();

            var message_num = context.MessagePushs.Where(s => s.IsRead == false && s.MerchantId == userId && (s.Type == MsgType.None || s.Type >= MsgType.BazaarPass)).Count();

            return notice_count + message_num;
        }

        /// <summary>
        /// 消息列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public List<message_item_ex> GetNoticMessageEx(long userId) {
            var result = new List<message_item_ex>();
            var user = _merchantService.Get(userId);
            //公告
            var q = (from n in context.Notice
                     join nu in context.NoticeUserReadHis.Where(o => o.UserId == userId) on n.Id equals nu.NoticeId into t1
                     from tnu in t1.DefaultIfEmpty()
                     where n.Status == ENoticeStatus.Published && n.Type == ENoticeType.APP && n.CreateTime > user.create_time && (tnu == null || tnu.IsDeleted == false)
                     select new { n.Id, n.CreateTime, n.Content, IsRead = tnu != null ? true : false });
            var notice_count = q.Where(s => s.IsRead == false).Count();
            string message_title = string.Empty;
            var notice_one = q.OrderByDescending(s => s.CreateTime).FirstOrDefault();
            if (notice_one != null)
                message_title = notice_one.Content;
            result.Add(new message_item_ex { number = notice_count, icon = RequestMethod.token_imgurl + "msg/notice.png", message_title = message_title, title = "官方公告", type = 0 });
            //商城消息
            var qx = context.MessagePushs.Where(s => s.MerchantId == userId && ((s.Type >= MsgType.BazaarPass && s.Type < MsgType.TransferProftFail) || s.Type == MsgType.None));
            notice_count = qx.Where(s => s.IsRead == false).Count();
            var message_one = qx.OrderByDescending(s => s.CreateTime).FirstOrDefault();
            if (message_one != null)
                message_title = message_one.ShortContent;
            else
                message_title = string.Empty;
            result.Add(new message_item_ex { number = notice_count, icon = RequestMethod.token_imgurl + "msg/shop.png", message_title = message_title, title = "商城消息", type = 1 });
            //通知消息
            qx = context.MessagePushs.Where(s => s.MerchantId == userId && (s.Type >= MsgType.TransferProftFail && s.Type < MsgType.UserFeedBack));
            notice_count = qx.Where(s => s.IsRead == false).Count();
            message_one = qx.OrderByDescending(s => s.CreateTime).FirstOrDefault();
            if (message_one != null)
                message_title = message_one.ShortContent;
            else
                message_title = string.Empty;
            result.Add(new message_item_ex { number = notice_count, icon = RequestMethod.token_imgurl + "msg/message.png", message_title = message_title, title = "通知消息", type = 2 });
            //客服消息
            qx = context.MessagePushs.Where(s => s.MerchantId == userId && (s.Type >= MsgType.UserFeedBack && s.Type <= MsgType.ServiceTo));
            notice_count = qx.Where(s => s.IsRead == false).Count();
            message_one = qx.OrderByDescending(s => s.CreateTime).FirstOrDefault();
            if (message_one != null)
                message_title = message_one.ShortContent;
            else
                message_title = string.Empty;
            result.Add(new message_item_ex { number = notice_count, icon = RequestMethod.token_imgurl + "msg/servce.png", message_title = message_title, title = "客服消息", type = 3 });

            return result;
        }

        /// <summary>
        /// APP逻辑删除公告阅读记录
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public int APPDeleteNotice(long id, long userId) {
            var his = context.NoticeUserReadHis.Where(o => o.NoticeId == id && o.UserId == userId).FirstOrDefault();
            if (his == null) {//阅读记录不存在，创建一条已删除的阅读记录
                his = new NoticeUserReadHis() { NoticeId = id, UserId = userId, CreateTime = DateTime.Now, IsDeleted = true };
                context.NoticeUserReadHis.Add(his);
            } else {
                his.IsDeleted = true;
            }
            int result = _iUnitOfWork.Commit("NoticeUserReadHis");
            return result;
        }
        #endregion

        #region 拓垦合伙人营销系统
        /// <summary>
        /// 获得合伙人系统公告列表
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public PagedResult<markting_notice_dto> GetMarktingNoticePageList(PageQuery query, long userId) {
            var q = from n in context.Notice
                    join nu in context.NoticeUserReadHis.Where(o => o.UserId == userId) on n.Id equals nu.NoticeId into t1
                    from tnu in t1.DefaultIfEmpty()
                    where (n.Status == ENoticeStatus.Published && (n.Type == ENoticeType.Marketing) && (tnu == null || tnu.IsDeleted == false))
                    select new markting_notice_dto() {
                        id = n.Id,
                        title = n.Title,
                        release_time = n.ReleaseTime,
                        isRead = tnu != null ? true : false
                    };
            var rows = q.OrderByDescending(c => c.release_time).Skip((query.page - 1) * query.size).Take(query.size).ToList();
            var result = new PagedResult<markting_notice_dto>(rows, q.Count(), query.page, query.size);
            return result;
        }
        /// <summary>
        /// 获得合伙人系统公告详情
        /// </summary>
        /// <returns></returns>
        public markting_notice_dto_ex GetMarktingNotice(long id, long userId) {
            notice_dto dto = AppGetNotice(id, userId);
            markting_notice_dto_ex result = new markting_notice_dto_ex();
            dto.ToCopyProperty(result);
            result.isRead = true;
            //result.pre_id = context.Notice.Where(o => o.Status == ENoticeStatus.Published && (o.Type == ENoticeType.All || o.Type == ENoticeType.Marketing)
            //                                         && o.ReleaseTime > result.release_time).OrderBy(o => o.ReleaseTime).Select(o => o.Id).FirstOrDefault();
            //result.next_id = context.Notice.Where(o => o.Status == ENoticeStatus.Published && (o.Type == ENoticeType.All || o.Type == ENoticeType.Marketing)
            //                                        && o.ReleaseTime < result.release_time).OrderByDescending(o => o.ReleaseTime).Select(o => o.Id).FirstOrDefault();
            return result;
        }

        #endregion

        ///// <summary>
        ///// 更新自动发布状态  TODO:后续可考虑改为定时任务
        ///// </summary>
        //private void AutoPublish()
        //{
        //    var list = context.Notice.Where(o => o.Status == ENoticeStatus.Unpublished && o.ReleaseTime != null && o.ReleaseTime <= DateTime.Now).ToList();
        //    if (list == null || list.Count() == 0)
        //        return;
        //    list.ForEach(o => { o.Status = ENoticeStatus.Published; });
        //    _iUnitOfWork.Commit("Notice");
        //    foreach (var notice in list)
        //    {
        //        PushNotice(notice.Id);
        //    }
        //}

        /// <summary>
        /// 推送公告
        /// </summary>
        /// <param name="id"></param>
        private void PushNotice(long id) {
            JPushHelp jPushHelp = new JPushHelp(t_RequestMethod.push_app_key, t_RequestMethod.push_app_secret);
            var notice = context.Notice.FindById(id);
            if (notice.Type == ENoticeType.Marketing) return;
#if !DEBUG
            if (!string.IsNullOrEmpty(notice.Url))
                jPushHelp.Push(notice.Title, notice.Content, 1, notice.Id, null, notice.Url);
            else
                jPushHelp.Push(notice.Title, notice.Content, 1, notice.Id, null);
#else
            if (!string.IsNullOrEmpty(notice.Url))
                jPushHelp.Push(notice.Title, notice.Content, 1, notice.Id, new List<string>() { "15659267689", "17859905531", "13599902194" }, notice.Url);
            else
                jPushHelp.Push(notice.Title, notice.Content, 1, notice.Id, new List<string>() { "15659267689", "17859905531", "13599902194" });
#endif

        }
    }
}
